﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Text.Editor;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Utilities;
using TwitterAPI;
using System.Timers;
using System.Windows.Controls;
using System.Windows;
using VsSpeakerCompanion.UI;

namespace VsSpeakerCompanion
{
    internal class WidgetManager : IVisualStudioService
    {
        private Context context;
        private Timer timer;
        private TwitterService twitterService;
        private List<IWpfTextView> views;
        private SidebarPresenter sidebarPresenter;
        private IUIService uiService;

        private IServiceProvider serviceProvider;

        private static WidgetManager instance;

        private WidgetManager()
        {
            this.context = new Context();
            this.views = new List<IWpfTextView>();
            this.twitterService = new TwitterService();
            this.timer = new Timer(3000);
            this.uiService = new UIService(this);
        }

        internal static WidgetManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WidgetManager();
                }

                return instance;
            }
        }

        internal void Add(IWpfTextView view)
        {
            this.views.Add(view);
            AddWidgetsToTheView(view);
            SubscribeToViewEvents(view);
        }

        private void SubscribeToViewEvents(IWpfTextView view)
        {
            view.VisualElement.IsVisibleChanged += new DependencyPropertyChangedEventHandler(OnViewVisualElementIsVisibleChanged);
            view.VisualElement.SizeChanged += new SizeChangedEventHandler(OnViewVisualElementSizeChanged);
            view.ViewportLeftChanged += new EventHandler(OnViewViewportLeftChanged);
            view.Closed += new EventHandler(OnViewClosed);
        }

        private void UnsubscribeFromViewEvents(IWpfTextView view)
        {
            view.VisualElement.IsVisibleChanged -= new DependencyPropertyChangedEventHandler(OnViewVisualElementIsVisibleChanged);
            view.VisualElement.SizeChanged -= new SizeChangedEventHandler(OnViewVisualElementSizeChanged);
            view.ViewportLeftChanged -= new EventHandler(OnViewViewportLeftChanged);
            view.Closed -= new EventHandler(OnViewClosed);
        }

        private void OnViewViewportLeftChanged(object sender, EventArgs e)
        {
            IWpfTextView view = sender as IWpfTextView;
            this.sidebarPresenter.Dock(view);
        }

        private void OnViewVisualElementIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue == true)
            {
                IWpfTextView targetView = this.views.FirstOrDefault(view => view.VisualElement == sender);

                if (targetView != null)
                {
                    AddWidgetsToTheView(targetView);
                }
            }
        }

        private void OnViewVisualElementSizeChanged(object sender, SizeChangedEventArgs e)
        {
            IWpfTextView targetView = this.views.FirstOrDefault(view => view.VisualElement == sender);

            if (targetView != null)
            {
                this.sidebarPresenter.Dock(targetView);
            }
        }

        internal bool IsInitialized { get; private set; }

        internal void Initialize(IEnumerable<IWidgetProvider> providers)
        {
            if (!IsInitialized)
            {
                // Subscribi to the context events
                this.context.SessionStarting += new EventHandler(OnContextSessionStarting);
                this.context.SessionEnding += new EventHandler(OnContextSessionEnding);
                this.context.SessionStarted += new EventHandler(OnContextSessionStarted);
                this.context.SessionEnded += new EventHandler(OnContextSessionEnded);
                this.context.Settings.Load();

                // Initialize timer
                this.timer.Elapsed += new ElapsedEventHandler(TimerElapsed);

                this.sidebarPresenter = new SidebarPresenter(this, this.context, this.uiService);

                // Initialize widgets
                foreach (IWidgetProvider provider in providers)
                {
                    foreach (IWidget widget in provider.GetWidgets(context))
                    {
                        sidebarPresenter.Add(widget);
                    }
                }

                IsInitialized = true;
            }
        }

        private void OnContextSessionStarting(object sender, EventArgs e)
        {
            this.twitterService.Reset();
            this.sidebarPresenter.Reset();
            this.timer.Start();
        }

        private void OnContextSessionEnding(object sender, EventArgs e)
        {
            this.timer.Stop();
        }

        private void OnContextSessionStarted(object sender, EventArgs e)
        {
            this.context.Settings.Save();
        }

        private void OnContextSessionEnded(object sender, EventArgs e)
        {
            this.context.Settings.Save();
        }

        private void OnViewClosed(object sender, EventArgs e)
        {
            IWpfTextView view = sender as IWpfTextView;
            RemoveWidgetsFromTheView(view);
            UnsubscribeFromViewEvents(view);
            this.views.Remove(view);
        }

        private void AddWidgetsToTheView(IWpfTextView view)
        {
            IWpfTextView previousViewWithWidgets = GetActiveTextView();

            if (previousViewWithWidgets != null)
            {
                RemoveWidgetsFromTheView(previousViewWithWidgets);
            }

            view.Properties.AddProperty(typeof(WidgetManager), this);
            this.sidebarPresenter.Dock(view);

            IAdornmentLayer layer = GetAdornmentLayer(view);
            layer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, null, this, this.sidebarPresenter.VisualElement, null);
        }

        private IAdornmentLayer GetAdornmentLayer(IWpfTextView view)
        {
            return view.GetAdornmentLayer("VS Speaker Adornments Layer");
        }

        private void RemoveWidgetsFromTheView(IWpfTextView view)
        {
            if (view != null)
            {
                view.Properties.RemoveProperty(typeof(WidgetManager));
                IAdornmentLayer adornmentLayer = GetAdornmentLayer(view);
                adornmentLayer.RemoveAdornmentsByTag(this);
            }
        }

        private void TimerElapsed(object source, ElapsedEventArgs e)
        {
            try
            {
                twitterService.ProcessMessages(ex => Logger.Log(ex));
            }
            catch(Exception ex)
            {
                Logger.Log(ex);
            }
        }

        public IWpfTextView GetActiveTextView()
        {
            return this.views.FirstOrDefault(view => view.Properties.ContainsProperty(typeof(WidgetManager)));
        }

        public System.IServiceProvider ServiceProvider
        {
            get { return this.serviceProvider; }
            set { this.serviceProvider = value; }
        }

        internal TwitterService TwitterService
        {
            get { return this.twitterService; }
        }

        internal IUIService UIService
        {
            get { return this.uiService; }
        }
    }
}